package logger

import (
	"fmt"
	"io"
	"math/rand"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"time"

	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/sirupsen/logrus"
)

const (
	PanicLevel int = iota
	FatalLevel
	ErrorLevel
	WarnLevel
	InfoLevel
	DebugLevel
	TraceLevel
)

type Config struct {
	Level          int    `json:"level"`
	Dir            string `json:"dir"`
	FilenamePrefix string `json:"filenamePrefix"`
	MaxSizeMB      int    `json:"maxSizeMB"`
	MaxAgeDays     int    `json:"maxAgeDays"`
	MaxBackupFiles int    `json:"maxBackupFiles"`
}

func init() {
	logrus.SetFormatter(&logrus.TextFormatter{
		// FullTimestamp: true,
		// DisableColors: true,
		CallerPrettyfier: func(f *runtime.Frame) (string, string) {

			_, file, line, ok := runtime.Caller(8)
			if !ok {
				return "", ""
			}

			filename := filepath.Base(file)
			return "", fmt.Sprintf("%s:%d", filename, line)
		},
	})

	logrus.SetReportCaller(true)
}

func InitializeLogger(conf *Config) {
	if conf == nil {
		return
	}

	filename := path.Join(conf.Dir, conf.FilenamePrefix)

	rlWriter, err := rotatelogs.New(
		filename+".%Y%m%d.log",                                             // 日志文件命名模式
		rotatelogs.WithLinkName(filename+".log"),                           // 可选：创建一个符号链接到最新的日志文件
		rotatelogs.WithMaxAge(24*time.Hour*time.Duration(conf.MaxAgeDays)), // 日志文件最大保留时间
		rotatelogs.WithRotationSize(int64(conf.MaxSizeMB)*1024*1024),       // 日志轮转间隔时间
		rotatelogs.WithRotationCount(uint(conf.MaxBackupFiles)),
	)
	if err != nil {
		logrus.Fatalf("failed to create rotatelogs writer: %v", err)
	}

	logrus.SetOutput(io.MultiWriter(os.Stdout, rlWriter))
	logrus.SetLevel(logrus.Level(conf.Level))
}

func SetLoggerLevel(level int) {
	logrus.SetLevel(logrus.Level(level))
}

type Logger struct {
	logger *logrus.Logger
	reqId  string
}

func NewLogger(reqId string) *Logger {
	if reqId == "" {
		reqId = getRandomId(12)
	}
	return &Logger{
		reqId:  reqId,
		logger: logrus.StandardLogger(),
	}
}

func NewLogger2(logger *Logger) *Logger {
	var reqId string
	if logger == nil {
		reqId = getRandomId(12)
	} else {
		reqId = logger.reqId
	}
	return &Logger{
		reqId:  reqId,
		logger: logrus.StandardLogger(),
	}
}

func getRandomId(strSize uint32) string {
	randomStr := func() string {
		bytes := []byte("abcdefghijklmnopqrstuvwxyz1234567890")
		result := make([]byte, strSize)
		for i := 0; i < int(strSize); i++ {
			result[i] = bytes[rand.Int31()%36]
		}
		return string(result)
	}()
	return randomStr
}

func (l *Logger) Debugf(format string, args ...interface{}) {
	l.logger.WithField("reqId", l.reqId).Debugf(format, args...)
}

func (l *Logger) Tracef(format string, args ...interface{}) {
	l.logger.WithField("reqId", l.reqId).Tracef(format, args...)
}

func (l *Logger) Infof(format string, args ...interface{}) {
	l.logger.WithField("reqId", l.reqId).Infof(format, args...)
}

func (l *Logger) Warnf(format string, args ...interface{}) {
	l.logger.WithField("reqId", l.reqId).Warnf(format, args...)
}

func (l *Logger) Errorf(format string, args ...interface{}) {
	l.logger.WithField("reqId", l.reqId).Errorf(format, args...)
}

func (l *Logger) Fatalf(format string, args ...interface{}) {
	l.logger.WithField("reqId", l.reqId).Fatalf(format, args...)
}

func (l *Logger) Panicf(format string, args ...interface{}) {
	l.logger.WithField("reqId", l.reqId).Panicf(format, args...)
}
